import { ScreenController } from '@smart-cabinet-packages/screen'
import { getCabinetConfig, getScreenConfig } from './utils/config'
import logger from './utils/logger'

// 屏幕模块状态
interface ScreenModuleState {
  initialized: boolean
  connected: boolean
  lastError: Error | null
  lastCommandTime: Date | null
}

const screenState: ScreenModuleState = {
  initialized: false,
  connected: false,
  lastError: null,
  lastCommandTime: null,
}

let cabinetConfig: any
let screenConfig: any
let screen: ScreenController | null = null
let controlIds: any

const COMMAND_TIMEOUT = 3000 // 3秒

/**
 * 安全加载屏幕配置
 */
function loadScreenConfiguration(): boolean {
  try {
    cabinetConfig = getCabinetConfig()
    screenConfig = getScreenConfig()

    // 验证配置完整性
    if (!screenConfig) {
      throw new Error('屏幕配置加载失败')
    }

    if (!screenConfig.serialPort || !screenConfig.serialPort.path) {
      throw new Error('屏幕串口路径配置无效')
    }

    if (!screenConfig.serialPort.baudRate || screenConfig.serialPort.baudRate <= 0) {
      throw new Error('屏幕串口波特率配置无效')
    }

    if (!screenConfig.controlIds) {
      throw new Error('屏幕控制ID配置无效')
    }

    if (!cabinetConfig) {
      throw new Error('柜子配置加载失败')
    }

    controlIds = screenConfig.controlIds

    return true
  }
  catch (error) {
    const err = error as Error
    screenState.lastError = err
    logger.error('屏幕模块: 配置加载失败', {
      error: err.message,
      solution: '请检查config.json文件中的hardware.screen配置项是否正确',
    })
    return false
  }
}

/**
 * 创建屏幕控制器连接
 */
async function createScreenConnection(): Promise<boolean> {
  try {
    logger.info('屏幕模块: 正在连接屏幕串口...', {
      path: screenConfig.serialPort.path,
      baudRate: screenConfig.serialPort.baudRate,
    })

    screen = new ScreenController({
      type: 'serial',
      path: screenConfig.serialPort.path,
      baudRate: screenConfig.serialPort.baudRate,
    })

    // 设置连接超时
    const connectPromise = screen.connect()
    const timeoutPromise = new Promise((_, reject) => {
      setTimeout(() => reject(new Error('连接超时')), COMMAND_TIMEOUT)
    })

    await Promise.race([connectPromise, timeoutPromise])

    screenState.connected = true
    screenState.lastError = null

    logger.info('屏幕模块: 串口连接成功')
    return true
  }
  catch (error) {
    const err = error as Error
    screenState.connected = false
    screenState.lastError = err

    let solution = '请检查屏幕设备连接和串口配置'
    if (err.message.includes('permission') || err.message.includes('access')) {
      solution = '请检查串口权限，确保当前用户有访问串口设备的权限'
    }
    else if (err.message.includes('no such file') || err.message.includes('ENOENT')) {
      solution = '串口设备不存在，请检查设备是否正确连接'
    }
    else if (err.message.includes('timeout') || err.message.includes('连接超时')) {
      solution = '屏幕连接超时，请检查设备是否正常工作'
    }
    else if (err.message.includes('busy')) {
      solution = '串口设备被占用，请检查是否有其他程序正在使用该串口'
    }

    logger.error(`屏幕模块连接失败: ${err.message}`, {
      error: err.message,
      solution,
    })

    return false
  }
}

/**
 * 初始化屏幕模块
 */
export async function initScreen(): Promise<void> {
  logger.info('屏幕模块: 正在初始化...')
  try {
    // 重置状态
    screenState.initialized = false
    screenState.connected = false
    screenState.lastError = null

    // 加载配置
    if (!loadScreenConfiguration()) {
      throw new Error('配置加载失败')
    }

    // 创建连接
    const connectionSuccess = await createScreenConnection()
    if (!connectionSuccess) {
      throw new Error('屏幕控制器连接失败')
    }

    // 初始化显示
    await initScreenDisplay()

    screenState.initialized = true
  }
  catch (error) {
    const err = error as Error
    screenState.lastError = err

    logger.error(`屏幕模块初始化失败: ${err.message}`, {
      error: err.message,
      solution: '请检查屏幕设备连接和配置文件',
    })

    throw err
  }
}

/**
 * 安全发送屏幕命令
 */
async function safeSendCommand(id: string, command: string, _description: string): Promise<boolean> {
  try {
    if (!screen || !screenState.connected) {
      logger.warn('屏幕模块未连接，无法发送命令')
      return false
    }

    // 设置命令超时
    const sendPromise = screen.sendCommand(id, command)
    const timeoutPromise = new Promise((_, reject) => {
      setTimeout(() => reject(new Error('命令发送超时')), COMMAND_TIMEOUT)
    })

    await Promise.race([sendPromise, timeoutPromise])

    screenState.lastCommandTime = new Date()

    return true
  }
  catch (error) {
    const err = error as Error
    logger.error(`屏幕模块命令发送失败: ${err.message}`, {
      error: err.message,
      solution: '请检查屏幕设备连接状态',
    })

    screenState.connected = false
    return false
  }
}

/**
 * 初始化屏幕显示内容
 */
async function initScreenDisplay(): Promise<void> {
  try {
    const { cabinetIndex, fileCount, userName, status } = controlIds

    const commandList = [
      {
        id: cabinetIndex,
        command: `${cabinetConfig.index}`,
        description: '柜子编号',
      },
      {
        id: fileCount,
        command: ' 在柜文件:0',
        description: '文件数量',
      },
      {
        id: userName,
        command: `   ${cabinetConfig.name}`,
        description: '用户名称',
      },
      {
        id: status,
        command: '',
        description: '状态信息',
      },
    ]

    for (const cmd of commandList) {
      await safeSendCommand(cmd.id, cmd.command, cmd.description)

      // 命令间添加小延迟，避免过快发送
      await new Promise(resolve => setTimeout(resolve, 100))
    }
  }
  catch (error) {
    const err = error as Error
    logger.error('屏幕模块: 显示内容初始化失败', {
      error: err.message,
      solution: '请检查屏幕设备状态和配置',
    })
    throw err
  }
}

/**
 * 更新屏幕文件数量显示
 */
export async function updateScreen(count: number): Promise<void> {
  try {
    const command = ` 在柜文件:${count}`
    const { fileCount } = controlIds

    const success = await safeSendCommand(fileCount, command, '文件数量更新')
    if (!success) {
      logger.warn('屏幕模块: 文件数量更新失败', { count })
    }
  }
  catch (error) {
    const err = error as Error
    logger.error('屏幕模块: 更新文件数量时发生错误', {
      count,
      error: err.message,
    })
  }
}

/**
 * 更新屏幕倒计时显示
 */
export async function updateCountdown(countdown: number): Promise<void> {
  try {
    const body = countdown === 0 ? '' : `  检测中-${countdown}`
    const { status } = controlIds

    const success = await safeSendCommand(status, body, '倒计时更新')
    if (!success) {
      logger.warn('屏幕模块: 倒计时更新失败', { countdown })
    }
  }
  catch (error) {
    const err = error as Error
    logger.error('屏幕模块: 更新倒计时时发生错误', {
      countdown,
      error: err.message,
    })
  }
}

/**
 * 获取屏幕模块状态
 */
export function getScreenStatus(): ScreenModuleState {
  return { ...screenState }
}

/**
 * 清理屏幕模块资源
 */
export async function cleanupScreen(): Promise<void> {
  try {
    logger.info('屏幕模块: 开始清理资源...')

    // 关闭屏幕连接
    if (screen) {
      try {
        screen.disconnect()
        logger.info('屏幕模块: 连接已断开')
      }
      catch (error) {
        logger.warn('屏幕模块: 断开连接时发生错误', {
          error: (error as Error).message,
        })
      }
      screen = null
    }

    screenState.connected = false
    screenState.initialized = false

    logger.info('屏幕模块: 资源清理完成')
  }
  catch (error) {
    const err = error as Error
    logger.error('屏幕模块: 资源清理失败', {
      error: err.message,
    })
  }
}
